/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package br.com.saber.certificacao.modelos;

import br.com.saber.certificacao.modelos.relacionamentos.ProfessorVersao;
import br.com.saber.certificacao.modelos.relacionamentos.VersaoQuestao;
import br.com.saber.certificacao.modelos.validadores.interfaces.ValidadoInterface;
import java.util.Date;
import java.util.Set;
import java.util.TreeSet;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

/**
 *  Versão representa a versão da certificação.
 * Pro exemplo, a certificação SCJP possui versão 5, 6, 7.
 * Para cada número teremos uma classe versão, com a mesma certificação pai.
 * @author gbvbahia
 * @update 22/08/2011 Ainda não altrado no banco de produção!!!
 *  ALTER TABLE `sabercertificacao`.`versoes` ADD COLUMN `mother` TINYINT(1) UNSIGNED AFTER `certificacao_id`;
update sabercertificacao.versoes set mother = 0;
 *  ALTER TABLE `sabercertificacao`.`versoes` MODIFY COLUMN `mother` TINYINT(1) UNSIGNED NOT NULL;
 *  ALTER TABLE `sabercertificacao`.`versoes` ADD COLUMN `id_versao_mother` BIGINT(20) UNSIGNED AFTER `mother`;
 *  ALTER TABLE `sabercertificacao`.`versoes` MODIFY COLUMN `id_versao_mother` BIGINT(20) DEFAULT NULL,
 *  ADD CONSTRAINT `FK_versao_mother` FOREIGN KEY `FK_versao_mother` (`id_versao_mother`)
 *  REFERENCES `versoes` (`id`)
 *  ON DELETE RESTRICT
 *  ON UPDATE RESTRICT;
 */
@Entity
@Table(name = "versoes")
public class Versao implements ValidadoInterface, Comparable<Versao> {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id", nullable = false, unique = true)
    private Long id;

    @Column(name = "versao_nome", nullable = false, unique = true, length = 50)
    private String nome;

    @Column(name = "nota_minima_real", nullable = false, unique = false)
    private Double notaParaPassar;

    @Temporal(TemporalType.TIME)
    @Column(name = "tempo_max_prova_real", nullable = false, unique = false)
    private Date tempoProvaReal;

    @Column(name = "total_questoes_real", nullable = false, unique = false)
    private Integer totalQuestoesReal;

    @Column(name = "site_oficial", nullable = false, unique = false, length = 255)
    private String urlSiteOficial;

    @Column(name = "mother", nullable = false, unique = false)
    private boolean mother = false;

    @ManyToOne(targetEntity = br.com.saber.certificacao.modelos.Versao.class)
    @JoinColumn(name = "id_versao_mother", referencedColumnName = "id")
    private Versao versaoMother;

    @OneToMany(targetEntity = br.com.saber.certificacao.modelos.relacionamentos.ProfessorVersao.class, fetch = FetchType.LAZY,
    mappedBy = "versao", cascade = CascadeType.MERGE)
    private Set<ProfessorVersao> professoresDestaVersao;

    @OneToMany(targetEntity = br.com.saber.certificacao.modelos.relacionamentos.VersaoQuestao.class, fetch = FetchType.LAZY,
    mappedBy = "versao", cascade = CascadeType.MERGE)
    private Set<VersaoQuestao> questoesDestaVersao;

    @ManyToOne(targetEntity = br.com.saber.certificacao.modelos.Certificacao.class, fetch = FetchType.EAGER)
    @JoinColumn(name = "certificacao_id", referencedColumnName = "id", nullable = false)
    private Certificacao certificacao;

    /**
     * FetchType.LAZY
     * Representa todas as questões que estão vinculadas a esta versão de certificação.
     * Uma questão pode ficar ligada a mais de uma certificação.
     * @return Todas as questões desta sertificação.
     */
    public Set<VersaoQuestao> getQuestoesDestaVersao() {
        if (this.questoesDestaVersao == null) {
            this.questoesDestaVersao = new TreeSet<VersaoQuestao>();
        }
        return questoesDestaVersao;
    }

    /**
     * FetchType.LAZY
     * Representa todas as questões que estão vinculadas a esta versão de certificação.
     * Uma questão pode ficar ligada a mais de uma certificação.
     * @param questoesDestaVersao
     */
    public void setQuestoesDestaVersao(Set<VersaoQuestao> questoesDestaVersao) {
        this.questoesDestaVersao = questoesDestaVersao;
    }

    /**
     * FetchType.EAGER
     * Representa a certificação em que esta versão está contida.
     * @return
     */
    public Certificacao getCertificacao() {
        return certificacao;
    }

    /**
     * FetchType.EAGER
     * Representa a certificação em que esta versão está contida.
     * @param certificacao
     */
    public void setCertificacao(Certificacao certificacao) {
        this.certificacao = certificacao;
    }

    /**
     * FetchType.LAZY
     * Representa todos os rofessores que podem cadastrar questões nesta versão.
     * @return
     */
    public Set<ProfessorVersao> getProfessoresDestaVersao() {
        if (this.professoresDestaVersao == null) {
            professoresDestaVersao = new TreeSet<ProfessorVersao>();
        }
        return professoresDestaVersao;
    }

    /**
     * FetchType.LAZY
     * Representa todos os rofessores que podem cadastrar questões nesta versão.
     * @param professoresDestaVersao
     */
    public void setProfessoresDestaVersao(Set<ProfessorVersao> professoresDestaVersao) {
        this.professoresDestaVersao = professoresDestaVersao;
    }

    public String getNome() {
        return nome;
    }

    public void setNome(String nome) {
        this.nome = nome;
    }

    public Double getNotaParaPassar() {
        return notaParaPassar;
    }

    public void setNotaParaPassar(Double notaParaPassar) {
        this.notaParaPassar = notaParaPassar;
    }

    public Date getTempoProvaReal() {
        return tempoProvaReal;
    }

    public void setTempoProvaReal(Date tempoProvaReal) {
        this.tempoProvaReal = tempoProvaReal;
    }

    public Integer getTotalQuestoesReal() {
        return totalQuestoesReal;
    }

    public void setTotalQuestoesReal(Integer totalQuestoesReal) {
        this.totalQuestoesReal = totalQuestoesReal;
    }

    public String getUrlSiteOficial() {
        return urlSiteOficial;
    }

    public void setUrlSiteOficial(String urlSiteOficial) {
        this.urlSiteOficial = urlSiteOficial;
    }

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public boolean isMother() {
        return mother;
    }

    public void setMother(boolean mother) {
        this.mother = mother;
    }

    public Versao getVersaoMother() {
        return versaoMother;
    }

    public void setVersaoMother(Versao versaoMother) {
        this.versaoMother = versaoMother;
    }

    @Override
    public int hashCode() {
        int hash = 0;
        hash += (id != null ? id.hashCode() : 0);
        return hash;
    }

    @Override
    public boolean equals(Object object) {
        // TODO: Warning - this method won't work in the case the id fields are not set
        if (!(object instanceof Versao)) {
            return false;
        }
        Versao other = (Versao) object;
        if ((this.id == null && other.id != null) || (this.id != null && !this.id.equals(other.id))) {
            return false;
        }
        return true;
    }

    @Override
    public String toString() {
        return "br.com.saber.certificacao.modelos.Versao[id=" + id + "]";
    }

    @Override
    public int compareTo(Versao o) {
        int toReturn = 0;
        if (toReturn == 0 && (this.mother && !o.isMother())) {
            toReturn = -1;
        }            
        if (toReturn == 0 && (!this.mother && o.isMother())) {
            toReturn = 1;
        }
        if (toReturn == 0) {
            toReturn = this.nome.compareTo(o.getNome());
        }
        if (toReturn == 0) {
            toReturn = this.id.compareTo(o.getId());
        }
        return toReturn;
    }

    public String versaoLabel() {
        if (this.nome != null) {
            return nome;
        }
        return null;
    }
}
